#ifndef __UTILS_H__
#define __UTILS_H__

#pragma once

namespace DuiLib
{
	/////////////////////////////////////////////////////////////////////////////////////
	//
	
	class STRINGorID
	{
	public:
		STRINGorID(LPCTSTR lpString) : m_lpstr(lpString)
		{ }
		STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID))
		{ }
		LPCTSTR m_lpstr;
	};

	class  UILIB_API OSVer  
	{
	public:

		virtual ~OSVer();
		static OSVer& Instance()
		{
			static OSVer __os;
			return __os;
		}

		// Returns service pack string
		LPCTSTR GetServicePack() const;

		// Returns true if OSver is 2003
		bool Is2003() const;

		// Returns true if OSVer is XP
		bool IsXP() const;

		// Returns true if OSVer is 2000
		bool Is2000() const;

		// Returns true if OSVer is windows 95
		bool IsWin95() const;

		// Returns true if OSVer is windows 98
		bool IsWin98() const;

		// Returns true if OSVer is windows ME
		bool IsWinME() const;

		// Returns true if OSVer is windows vista
		bool IsWinVista() const;

		// Returns true if OSVer is windows 7
		bool IsWin7() const ;

		// Returns true if OSVer is windows 8
		bool IsWin8() const;
		// Return OS Ver constant reference
		const OSVERSIONINFO& GetOSVer() const;

		int GetOsVerIndex() const;
	private:

		OSVer();

		// OSVer Version
		OSVERSIONINFO m_stOsVer;
	};

	inline OSVer::OSVer()
	{
		ZeroMemory( &m_stOsVer, sizeof( m_stOsVer ));
		m_stOsVer.dwOSVersionInfoSize = sizeof( m_stOsVer );
		GetVersionEx( &m_stOsVer );
	}

	inline OSVer::~OSVer()
	{}

	inline LPCTSTR OSVer::GetServicePack() const
	{
		return GetOSVer().szCSDVersion;
	}

	inline bool OSVer::IsWinVista() const 
	{
		return ( GetOSVer().dwPlatformId    == VER_PLATFORM_WIN32_NT &&
			GetOSVer().dwMajorVersion  == 6 &&
			GetOSVer().dwMinorVersion  == 0 );
	}

	inline bool OSVer::IsWin7() const 
	{
		return ( GetOSVer().dwPlatformId    == VER_PLATFORM_WIN32_NT &&
			GetOSVer().dwMajorVersion  == 6 &&
			GetOSVer().dwMinorVersion  == 1 );
	}

	inline bool OSVer::IsWin8() const 
	{
		return ( GetOSVer().dwPlatformId    == VER_PLATFORM_WIN32_NT &&
			GetOSVer().dwMajorVersion  == 6 &&
			GetOSVer().dwMinorVersion  == 2 );
	}

	inline bool OSVer::Is2003() const
	{
		return ( GetOSVer().dwPlatformId    == VER_PLATFORM_WIN32_NT &&
			GetOSVer().dwMajorVersion  == 5 &&
			GetOSVer().dwMinorVersion  == 2 );
	}

	inline bool OSVer::IsXP() const
	{
		return ( GetOSVer().dwPlatformId   == VER_PLATFORM_WIN32_NT && 
			GetOSVer().dwMajorVersion == 5 && 
			GetOSVer().dwMinorVersion == 1 );
	}

	inline bool OSVer::Is2000() const
	{
		return ( GetOSVer().dwPlatformId   == VER_PLATFORM_WIN32_NT &&
			GetOSVer().dwMajorVersion == 5 && 
			GetOSVer().dwMinorVersion == 0 );
	}

	inline bool OSVer::IsWin95() const
	{
		return ( GetOSVer().dwPlatformId   == VER_PLATFORM_WIN32_WINDOWS &&
			GetOSVer().dwMajorVersion == 4 &&
			GetOSVer().dwMinorVersion == 0 );
	}

	inline bool OSVer::IsWin98() const
	{
		return ( GetOSVer().dwPlatformId   == VER_PLATFORM_WIN32_WINDOWS &&
			GetOSVer().dwMajorVersion == 4 &&
			GetOSVer().dwMinorVersion == 10 );
	}

	inline bool OSVer::IsWinME() const
	{
		return ( GetOSVer().dwPlatformId   == VER_PLATFORM_WIN32_WINDOWS &&
			GetOSVer().dwMajorVersion == 4 &&
			GetOSVer().dwMinorVersion == 90 );
	}

	inline int OSVer::GetOsVerIndex() const
	{
		return GetOSVer().dwMajorVersion;
	}

	inline const OSVERSIONINFO& OSVer::GetOSVer() const
	{
		return m_stOsVer;
	}

	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CDuiPoint : public tagPOINT
	{
	public:
		CDuiPoint();
		CDuiPoint(const POINT& src);
		CDuiPoint(int x, int y);
		CDuiPoint(LPARAM lParam);
	};


	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CSize : public tagSIZE
	{
	public:
		CSize();
		CSize(const SIZE& src);
		CSize(const RECT rc);
		CSize(int cx, int cy);
	};


	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CDuiRect : public tagRECT
	{
	public:
		CDuiRect();
		CDuiRect(const RECT& src);
		CDuiRect(int iLeft, int iTop, int iRight, int iBottom);

		int GetWidth() const;
		int GetHeight() const;
		void Empty();
		bool IsNull() const;
		void Join(const RECT& rc);
		void ResetOffset();
		void Normalize();
		void Offset(int cx, int cy);
		void Inflate(int cx, int cy);
		void Deflate(int cx, int cy);
		void Union(CDuiRect& rc);
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CStdPtrArray
	{
	public:
		CStdPtrArray(int iPreallocSize = 0);
		CStdPtrArray(const CStdPtrArray& src);
		~CStdPtrArray();

		void Empty();
		void Resize(int iSize);
		bool IsEmpty() const;
		int Find(LPVOID iIndex) const;
		bool Add(LPVOID pData);
		bool SetAt(int iIndex, LPVOID pData);
		bool InsertAt(int iIndex, LPVOID pData);
		bool Remove(int iIndex);
		int GetSize() const;
		LPVOID* GetData();

		LPVOID GetAt(int iIndex) const;
		LPVOID operator[] (int nIndex) const;

	protected:
		LPVOID* m_ppVoid;
		int m_nCount;
		int m_nAllocated;
	};


	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CStdValArray
	{
	public:
		CStdValArray(int iElementSize, int iPreallocSize = 0);
		~CStdValArray();

		void Empty();
		bool IsEmpty() const;
		bool Add(LPCVOID pData);
		bool Remove(int iIndex);
		int GetSize() const;
		LPVOID GetData();

		LPVOID GetAt(int iIndex) const;
		LPVOID operator[] (int nIndex) const;

	protected:
		LPBYTE m_pVoid;
		int m_iElementSize;
		int m_nCount;
		int m_nAllocated;
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CDuiString
	{
	public:
		enum { MAX_LOCAL_STRING_LEN = 63 };

		CDuiString();
		CDuiString(const TCHAR ch);
		CDuiString(const CDuiString& src);
		CDuiString(LPCTSTR lpsz, int nLen = -1);
		~CDuiString();

		void Empty();
		int GetLength() const;
		bool IsEmpty() const;
		TCHAR GetAt(int nIndex) const;
		void Append(LPCTSTR pstr);
		void Assign(LPCTSTR pstr, int nLength = -1);
		LPCTSTR GetData() const;

		void SetAt(int nIndex, TCHAR ch);
		operator LPCTSTR() const;

		TCHAR operator[] (int nIndex) const;
		const CDuiString& operator=(const CDuiString& src);
		const CDuiString& operator=(const TCHAR ch);
		const CDuiString& operator=(LPCTSTR pstr);
#ifdef _UNICODE
		const CDuiString& CDuiString::operator=(LPCSTR lpStr);
		const CDuiString& CDuiString::operator+=(LPCSTR lpStr);
#else
		const CDuiString& CDuiString::operator=(LPCWSTR lpwStr);
		const CDuiString& CDuiString::operator+=(LPCWSTR lpwStr);
#endif
		CDuiString operator+(const CDuiString& src) const;
		CDuiString operator+(LPCTSTR pstr) const;
		const CDuiString& operator+=(const CDuiString& src);
		const CDuiString& operator+=(LPCTSTR pstr);
		const CDuiString& operator+=(const TCHAR ch);

		bool operator == (LPCTSTR str) const;
		bool operator != (LPCTSTR str) const;
		bool operator <= (LPCTSTR str) const;
		bool operator <  (LPCTSTR str) const;
		bool operator >= (LPCTSTR str) const;
		bool operator >  (LPCTSTR str) const;

		int Compare(LPCTSTR pstr) const;
		int CompareNoCase(LPCTSTR pstr) const;

		void MakeUpper();
		void MakeLower();

		CDuiString Left(int nLength) const;
		CDuiString Mid(int iPos, int nLength = -1) const;
		CDuiString Right(int nLength) const;

		int Find(TCHAR ch, int iPos = 0) const;
		int Find(LPCTSTR pstr, int iPos = 0) const;
		int ReverseFind(TCHAR ch) const;
		int Replace(LPCTSTR pstrFrom, LPCTSTR pstrTo);

		int __cdecl Format(LPCTSTR pstrFormat, ...);
        int __cdecl Format(LPCTSTR pstrFormat, va_list Args);
		int __cdecl SmallFormat(LPCTSTR pstrFormat, ...);

	protected:
		LPTSTR m_pstr;
		TCHAR m_szBuffer[MAX_LOCAL_STRING_LEN + 1];
	};


	/////////////////////////////////////////////////////////////////////////////////////
	//

	struct TITEM
	{
		CDuiString Key;
		LPVOID Data;
		struct TITEM* pPrev;
		struct TITEM* pNext;
	};

	class UILIB_API CStdStringPtrMap
	{
	public:
		CStdStringPtrMap(int nSize = 83);
		~CStdStringPtrMap();

		void Resize(int nSize = 83);
		LPVOID Find(LPCTSTR key, bool optimize = true) const;
		bool Insert(LPCTSTR key, LPVOID pData);
		LPVOID Set(LPCTSTR key, LPVOID pData);
		bool Remove(LPCTSTR key);
		void RemoveAll();
		int GetSize() const;
		LPCTSTR GetAt(int iIndex) const;
		LPCTSTR operator[] (int nIndex) const;

	protected:
		TITEM** m_aT;
		int m_nBuckets;
		int m_nCount;
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//

	class UILIB_API CWaitCursor
	{
	public:
		CWaitCursor();
		~CWaitCursor();

	protected:
		HCURSOR m_hOrigCursor;
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//

	class CVariant : public VARIANT
	{
	public:
		CVariant() 
		{ 
			VariantInit(this); 
		}
		CVariant(int i)
		{
			VariantInit(this);
			this->vt = VT_I4;
			this->intVal = i;
		}
		CVariant(float f)
		{
			VariantInit(this);
			this->vt = VT_R4;
			this->fltVal = f;
		}
		CVariant(LPOLESTR s)
		{
			VariantInit(this);
			this->vt = VT_BSTR;
			this->bstrVal = s;
		}
		CVariant(IDispatch *disp)
		{
			VariantInit(this);
			this->vt = VT_DISPATCH;
			this->pdispVal = disp;
		}

		~CVariant() 
		{ 
			VariantClear(this); 
		}
	};

}// namespace DuiLib

#endif // __UTILS_H__